package com.stark.wechat.controller;

import java.io.IOException;
import java.io.UnsupportedEncodingException;

import org.dom4j.DocumentException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.stark.wechat.context.ScopeUtil;
import com.stark.wechat.form.Result;
import com.stark.wechat.service.impl.AccessServiceImpl;
import com.stark.wechat.util.SysTools;
import com.stark.wechat.util.Tools;

/**
 * 微信接入控制器。
 * @author Ben
 * @since 1.0.0
 * @version 1.0.0, 2017/8/5
 */
@Controller
public class AccessController {
	Logger logger = LoggerFactory.getLogger(AccessController.class);
	
	@Autowired
	private AccessServiceImpl accessService;
	
	/**
	 * 微信接入验证。
	 * @param signature	微信加密签名， signature 结合了开发者填写的 token 参数和请求中的 timestamp 参数、 nonce 参数。
	 * @param timestamp 时间戳。
	 * @param nonce 随机数。
	 * @param echostr 随机字符串，验证通过时原样返回该参数。
	 * @return 验证通过时原样返回 echostr ，否则返回其他任意字符串。
	 */
	@GetMapping(value = "/access/handler", produces = "text/html;charset=UTF-8")
	@ResponseBody
	public String validate(String signature, String timestamp, String nonce, String echostr) {
		String result = this.accessService.validate(signature, timestamp, nonce, echostr);
		return result;
	}
	
	/**
	 * 微信消息处理。
	 * @return 消息处理结果。
	 * @throws DocumentException 读取 XML 时抛出异常。
	 * @throws IOException 获取输入流时抛出异常。
	 */
	@PostMapping(value = "/access/handler", produces = "application/xml;charset=UTF-8")
	@ResponseBody
	public String handelRequest() throws IOException, DocumentException {
        String result = this.accessService.handelRequest(ScopeUtil.getRequest());
    		return result;
	}
	
	/**
	 * 跳转链接。
	 * @param code 换取 access_token 的票据，每次用户授权带上的 code 将不一样， code 只能使用一次， 5 分钟未被使用自动过期。
	 * @param state 开发者可以自定义 a-zA-Z0-9 的参数值，最多 128 字节。
	 * @param link 跳转链接地址。
	 * @return 跳转链接。
	 */
	@GetMapping("/access/forward")
	public ModelAndView forward(String code, String state, String link) {
		Result result = SysTools.requestOauth2UserInfo(code);
		
		if (result.isSuccess()) {
			String openId = (String) result.getData().get("openid");
			try {
				link = SysTools.parseForwardLink(link);
			} catch (UnsupportedEncodingException e) {
				logger.error("解析跳转链接时出错", e);
				
				ModelAndView mav = new ModelAndView("info/error");
				mav.addObject("msg", "解析跳转链接时出错");
				mav.addObject("msgDesc", e.getMessage());
				return mav;
			}
			if (link.contains("{openId}")) {
				link = link.replaceAll("\\{openId\\}", openId);
			} else {
				link = Tools.concatURLQueryString(link, "openId=" + openId);
			}
			link = Tools.concatURLQueryString(link, "state=" + state);
			
			ModelAndView mav = new ModelAndView("redirect:" + link);
			return mav;
		}
		
		ModelAndView mav = new ModelAndView("info/error");
		mav.addObject("msg", result.getErrmsg());
		return mav;
	}
}
